'''
Created on 2009-11-19

@author: Jialai_Zhu
'''
import BaseHTTPServer
import SocketServer
import os
 
PORT = 9937

import mufs
import re
fs = mufs.mufs() 



__doc__ = """Tiny HTTP Proxy.

This module implements GET, HEAD, POST, PUT and DELETE methods
on BaseHTTPServer, and behaves as an HTTP proxy.  The CONNECT
method is also implemented experimentally, but has not been
tested yet.

Any help will be greatly appreciated.        SUZUKI Hisao
"""

__version__ = "0.2.1"

import BaseHTTPServer, select, socket, SocketServer, urlparse

class ProxyHandler (BaseHTTPServer.BaseHTTPRequestHandler):
    __base = BaseHTTPServer.BaseHTTPRequestHandler
    __base_handle = __base.handle

    server_version = "TinyHTTPProxy/" + __version__
    rbufsize = 0                        # self.rfile Be unbuffered

    def handle(self):
        (ip, port) = self.client_address
#        if hasattr(self, 'allowed_clients') and ip not in self.allowed_clients:
#            self.raw_requestline = self.rfile.readline()
#            if self.parse_request(): self.send_error(403)
#        else:
#            self.__base_handle()
        self.__base_handle()

    def _connect_to(self, netloc, soc):
        i = netloc.find(':')
        if i >= 0:
            host_port = netloc[:i], int(netloc[i + 1:])
        else:
            host_port = netloc, 80
        print "\t" "connect to %s:%d" % host_port
        try: soc.connect(host_port)
        except socket.error, arg:
            try: msg = arg[1]
            except: msg = arg
            self.send_error(404, msg)
            return 0
        return 1

    def do_CONNECT(self):
        soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            if self._connect_to(self.path, soc):
                self.log_request(200)
                self.wfile.write(self.protocol_version + 
                                 " 200 Connection established\r\n")
                self.wfile.write("Proxy-agent: %s\r\n" % self.version_string())
                self.wfile.write("\r\n")
                self._read_write(soc, 300)
        finally:
#            print "\t" "bye"
            soc.close()
            self.connection.close()
            
    def do_Local(self):
        path = self.path
        try:
            resp = fs.read(path)
            return resp
        except:
            p = '(.*?)://(.*?)/*[^/]*$'
            ret = re.search(p, path).groups()
            path = ret[0] + '://' + ret[1]
            resp = fs.read(path)
            return resp
            
    def do_GET(self):
        (scm, netloc, path, params, query, fragment) = urlparse.urlparse(
            self.path, 'http')
        if scm != 'http' or fragment or not netloc:
            self.send_error(400, "bad url %s" % self.path)
            return
        
        try:
            resp = self.do_Local()
            self.connection.send(resp)
            self.connection.close()
            self.log_request()
            print 'from local cache %s' % self.path
            return
        except:
#            self.send_error(400, "bad url %s" % self.path)
#            return
            pass    
        
        soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            if self._connect_to(netloc, soc):
                self.log_request()
                soc.send("%s %s %s\r\n" % (
                    self.command,
                    urlparse.urlunparse(('', '', path, params, query, '')),
                    self.request_version))
                self.headers['Connection'] = 'close'
                del self.headers['Proxy-Connection']
                for key_val in self.headers.items():
                    soc.send("%s: %s\r\n" % key_val)
                soc.send("\r\n")
                self._read_write(soc)
        finally:
#            print "\t" "bye"
            soc.close()
            self.connection.close()

    def _read_write(self, soc, max_idling=20):
        iw = [self.connection, soc]
        ow = []
        count = 0
        while 1:
            count += 1
            (ins, _, exs) = select.select(iw, ow, iw, 3)
            if exs: break
            if ins:
                for i in ins:
                    if i is soc:
                        out = self.connection
                    else:
                        out = soc
                    data = i.recv(8192)
                    if data:
                        out.send(data)
                        count = 0
            else:
#                print "\t" "idle", count
                pass
            if count == max_idling: break

    do_HEAD = do_GET
    do_POST = do_GET
    do_PUT = do_GET
    do_DELETE = do_GET

class ThreadingHTTPServer (SocketServer.ThreadingMixIn,
                           BaseHTTPServer.HTTPServer): pass


#try:
#    httpd = SocketServer.TCPServer(("", PORT), ProxyHandler)
#    httpd.serve_forever()
import configure
def run(address=None, port=None):
    if address == None:
        address = configure.address
    if port == None:
        port = configure.port    
    httpd = ThreadingHTTPServer((address, port), ProxyHandler)
    httpd.serve_forever()
#except:pass




#class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
##    def translate_path(self, path):
##        return SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(self,path)
#    def send_response(self,code,message):
#        path=self.path
#        try:resp=fs.read(path)
#        except:
#            p='(.*?)://(.*?)/*[^/]*$'
#            ret=re.search(p,path).groups()
#            path=ret[0]+'://'+ret[1]
#            try:
#                message='xxxxxxxxxxxxxxxxxx'
#                #fs.read(path) 
#                code=200
#            except Exception,ex:
#                pass
#        
#        
#        return BaseHTTPServer.BaseHTTPRequestHandler.send_response(self, code,message)
#try:
#    httpd = SocketServer.TCPServer(("", PORT), Handler)
#    httpd.serve_forever()
#except:pass

